package main

import (
	"fmt"
	"log"
	"reflect"
)

/*
 结构体  ——->  当成类
字段默认值：除基本数据类型外，其他类型字段默认值都为nil，包括（指针、函数、接口、切片、通道和映射）
*/
func main() {
	/**
	  1.简短方式创建结构体并赋值
	*/
	people := People{
		Age:      19, //也可不指定字段名，按顺序指定值，但不推荐
		Number:   "158231",
		Username: "小狗",
	}
	//{小狗 158231 19}
	fmt.Println(people)
	fmt.Println(people.Number)
	fmt.Println(people.Age)
	fmt.Println(people.Username)

	//2.创建结构体2，先声明再赋值
	var people2 People
	//没初始化的字段会初始化为零值 ：{  0}
	fmt.Println(people2)
	people2.Username = "小猫"
	fmt.Println(people2.Username)

	//3.New关键字创建结构体
	people3 := new(People)
	people3.Username = "小三"
	//TODO &{小三  0} ?为啥有&
	fmt.Println(people3)
	//qiantao()

	//compare()

	//valueReference()
	pointerReference()
}

/**
嵌套结构体创建
*/
func qiantao() {
	people := People{
		Username: "潇洒",
		Address: Address{
			address: "江苏省",
		},
	}
	fmt.Println("嵌套结构体")
	//{潇洒  0 {江苏省}}
	fmt.Println(people)
	fmt.Println(people.Address)
	fmt.Println(people.Address.address)
}

func compare() {
	people := People{
		Username: "哈哈",
		Address: Address{
			address: "江苏省",
		},
	}
	people2 := People{
		Username: "哈哈",
		Address: Address{
			address: "江苏省",
		},
	}
	/*address := Address{
		address: "江苏省",
	}*/
	//只能对相同类型的结构体进行==或!=比较，否则会编译错误
	if reflect.TypeOf(people) == reflect.TypeOf(people2) {
		fmt.Println(people2 == people)
	}
	//fmt.Println(people==address)
}

/**
  TODO 值引用(go默认)
*/
func valueReference() {
	fmt.Println("值引用...")
	addr := Address{
		address: "lala",
	}
	addr2 := addr
	addr2.address = "heihei"
	//addr2的修改没有影响addr
	fmt.Printf("%+v\n", addr)
	fmt.Printf("%+v\n", addr2)

	//0xc000010260
	fmt.Printf("%p\n", &addr)
	//0xc000010270
	fmt.Printf("%p", &addr2)

	//二者内存地址不同，说明是值引用，addr2为addr的副本
}

/**
指针引用
*/
func pointerReference() {
	fmt.Println("指针引用...")
	addr := Address{
		address: "lala",
	}
	addr2 := &addrbi
	addr2.address = "heihei"
	//addr2的修改影响addr
	fmt.Printf("%+v\n", addr)
	fmt.Printf("%+v\n", *addr2)

	//0xc000010260
	fmt.Printf("%p\n", &addr)
	//0xc000010260
	fmt.Printf("%p", addr2)

	//二者内存地址相同，说明是指针引用，addr2指向addr
}

type People struct {
	Username string
	Number   string
	Age      int
	Address
	// 匿名组合
	*log.Logger
}

type Address struct {
	address string
}

/*
	TODO Go规定，结构体及其数据宇段都可能被导出也可能不导出。如果一个标识首字母是大写的，那么它将被导出，否则不会导出
*/
